test-admin-deploy-switch \
test-admin-deploy-etcmerge-cornercases \
test-admin-deploy-uboot \
+ test-admin-upgrade-not-backwards \
test-setuid \
test-delta \
test-xattrs \
return NULL;
return ostree_checksum_from_bytes_v (bytes);
}
+
+guint64
+ostree_commit_get_timestamp (GVariant *commit_variant)
+{
+ guint64 ret;
+ g_variant_get_child (commit_variant, 5, "t", &ret);
+ return GUINT64_FROM_BE (ret);
+}
GError **error);
gchar * ostree_commit_get_parent (GVariant *commit_variant);
+guint64 ostree_commit_get_timestamp (GVariant *commit_variant);
G_END_DECLS
#include <glib/gi18n.h>
static gboolean opt_reboot;
+static gboolean opt_allow_downgrade;
static char *opt_osname;
static GOptionEntry options[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Specify operating system root to use", NULL },
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after a successful upgrade", NULL },
+ { "allow-downgrade", 0, 0, G_OPTION_ARG_NONE, &opt_allow_downgrade, "Permit deployment of chronologically older trees", NULL },
{ NULL }
};
else
{
gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/");
+
+ if (!opt_allow_downgrade)
+ {
+ const char *old_revision = ostree_deployment_get_csum (merge_deployment);
+ gs_unref_variant GVariant *old_commit = NULL;
+ gs_unref_variant GVariant *new_commit = NULL;
+
+ if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
+ old_revision,
+ &old_commit,
+ error))
+ goto out;
+
+ if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
+ new_revision, &new_commit,
+ error))
+ goto out;
+
+ if (ostree_commit_get_timestamp (old_commit) > ostree_commit_get_timestamp (new_commit))
+ {
+ GDateTime *old_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (old_commit));
+ GDateTime *new_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (new_commit));
+ gs_free char *old_ts_str = NULL;
+ gs_free char *new_ts_str = NULL;
+
+ g_assert (old_ts);
+ g_assert (new_ts);
+ old_ts_str = g_date_time_format (old_ts, "%c");
+ new_ts_str = g_date_time_format (new_ts, "%c");
+ g_date_time_unref (old_ts);
+ g_date_time_unref (new_ts);
+
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit",
+ new_revision, new_ts_str, old_revision, old_ts_str);
+ goto out;
+ }
+ }
/* Here we perform cleanup of any leftover data from previous
* partial failures. This avoids having to call gs_shutil_rm_rf()
ostree --repo=${test_tmpdir}/testos-repo commit -b testos/buildmaster/x86_64-runtime -s "Build"
+ # Ensure these commits have distinct second timestamps
+ sleep 2
echo "a new executable" > usr/bin/sh
ostree --repo=${test_tmpdir}/testos-repo commit -b testos/buildmaster/x86_64-runtime -s "Build"
setup_os_boot_uboot
;;
esac
+
+ cd ${test_tmpdir}
+ mkdir ${test_tmpdir}/httpd
+ cd httpd
+ ln -s ${test_tmpdir} ostree
+ ostree trivial-httpd --daemonize -p ${test_tmpdir}/httpd-port $args
+ port=$(cat ${test_tmpdir}/httpd-port)
+ echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address
+ cd ${oldpwd}
}
os_repository_new_commit ()
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2014 Colin Walters <walters@verbum.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+set -e
+
+. $(dirname $0)/libtest.sh
+
+echo "1..1"
+
+setup_os_repository "archive-z2" "syslinux"
+
+echo "ok setup"
+
+echo "1..2"
+
+cd ${test_tmpdir}
+ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo
+ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime
+rev=$(ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime)
+export rev
+echo "rev=${rev}"
+# This initial deployment gets kicked off with some kernel arguments
+ostree admin --sysroot=sysroot deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime
+assert_has_dir sysroot/boot/ostree/testos-${bootcsum}
+
+# This should be a no-op
+ostree admin --sysroot=sysroot upgrade --os=testos
+
+# Now reset to an older revision
+ostree --repo=${test_tmpdir}/testos-repo reset testos/buildmaster/x86_64-runtime{,^}
+
+if ostree admin --sysroot=sysroot upgrade --os=testos 2>upgrade-err.txt; then
+ assert_not_reached 'upgrade unexpectedly succeeded'
+fi
+assert_file_has_content upgrade-err.txt 'chronologically older'
+
+echo 'ok upgrade will not go backwards'
+
+ostree admin --sysroot=sysroot upgrade --os=testos --allow-downgrade
+
+echo 'ok upgrade backwards'